%{
  #include "type.h"
  #include <stdio.h>
  #include <stdlib.h>
  #include <string.h>
  #include "y.tab.h"

  const int MAX_LEN_NBR_REG = 5;
  instruction* headInstr = NULL;
  instruction* tailInstr = NULL;

  int nbr_type = 5;//On commence a compter à partir de 0. Il y a donc 8types de base
  int numLabel = 0;
  int derReg = 0;

  node* headVar;
  node* tailVar;

  node* headFunc;
  node* tailFunc;

  FILE* fichier;
  long position = 0;
  //  int hash_table[101];
  /* int hashage(char*c){ */
  /*   int n = 0; */
  /*   while(*c!='\0'){ */
  /*     n=n+8; */
  /*     *c++; */
  /*   } */
  /*   return n%101; */
  /* } */

  /* Cette fonction printe l'operation correspondant a son 
   *premier paramètre.
   *Son type de retour correspond au type de retour de 
   *l'opération.
   * Mots clé : add, sub, div, mul, and

   */

  int printCmd(char* op, variable* a, variable* b, variable* retour) {
    if(!strcmp(op, "add") || !strcmp(op, "sub") || !strcmp(op, "mul") || !strcmp(op, "div")) {
      if((a->type == INTEG || a->type == FLOA) && (b->type == INTEG || b->type == FLOA)) {
	if(a->type == b->type){
	  switch(a->type){
	  case(INTEG):
	    fprintf(fichier, "%s = %s i32 %s, %s\n", retour->nom, op, a->nom, b->nom);
	    return INTEG;
	    break;
	  case(FLOA):
	    fprintf(fichier, "%s = f%s float %s, %s\n", retour->nom, op, a->nom, b->nom);
	    break;
	  }
	}
	else if(a->type == INTEG){
	  fprintf(fichier, "%%%d = bitcast i32 %s to float\n", derReg, a->nom);
	  derReg++;
	  fprintf(fichier, "%s = f%s float %%%d, %s\n", retour->nom, op, derReg-1, b->nom);
	}
	else if(a->type == FLOA){
	  fprintf(fichier, "%%%d = bitcast i32 %s to float\n", derReg, b->nom);
	  derReg++;
	  fprintf(fichier, "%s = f%s float %s, %%%d\n", retour->nom,  op, a->nom, derReg-1);
	}
	else{
	  printf("La variable %s est inconnu pour l'op : %s", a->nom, op);
	}
	return FLOA;
      }
    }
    else if(!strcmp(op, "eq") || !strcmp(op, "ne")) {
      if(a->type == b->type){
	switch(a->type){
	case(INTEG):
	  fprintf(fichier, "%s = icmp %s i32 %s, %s\n", retour->nom,  op, a->nom, b->nom);
	  break;
	case(FLOA):
	  fprintf(fichier, "%s = fcmp o%s float %s, %s\n", retour->nom, op, a->nom, b->nom);
	  break;
	case(UINTEG):
	  fprintf(fichier, "%s = icmp %s i32 %s, %s\n", retour->nom, op, a->nom, b->nom);
	  break;
	default:
	  printf("Attention opération booleenes entre 2 objets dont le type n'accepte pas les operations booleenes->\n");
	}
      }
      else
	printf("Attention opération booléenne entre deux variable de type différents.");
      return BOOL;
    }
    else if(!strcmp(op, "ge") || !strcmp(op, "gt") || !strcmp(op, "lt")){
      if(a->type == b->type){
	switch(a->type){
	case(INTEG):
	  fprintf(fichier, "%s = icmp s%s i32 %s, %s\n", retour->nom,  op, a->nom, b->nom);
	  break;
	case(FLOA):
	  fprintf(fichier, "%s = fcmp o%s float %s, %s\n", retour->nom, op, a->nom, b->nom);
	  break;
	case(UINTEG):
	  fprintf(fichier, "%s = fcmp u%s i32 %s, %s\n", retour->nom, op, a->nom, b->nom);
	  break;
	default:
	  printf("Attention opération booleenes entre 2 objets dont le type n'accepte pas les operations booleenes.\n");
	}
      }
      else
	printf("Attention opération booléenne entre deux variable de type différents.");
      return BOOL;
    }
    else if(!strcmp(op, "le")){
      if(a->type == b->type){
	switch(a->type){
	case(INTEG):
	  fprintf(fichier, "%s = icmp use i32 %s, %s\n", retour->nom,  a->nom, b->nom);
	  break;
	case(FLOA):
	  fprintf(fichier, "%s = fcmp o%s float %s, %s\n", retour->nom, op, a->nom, b->nom);
	  break;
	case(UINTEG):
	  fprintf(fichier, "%s = fcmp u%s i32 %s, %s\n", retour->nom, op, a->nom, b->nom);
	  break;
	default:
	  printf("Attention opération booleenes entre 2 objets dont le type n'accepte pas les operations booleenes.\n");
	}
      }
      else
	printf("Attention opération booléenne entre deux variable de type différents.");
      return BOOL;
    }
    else if(!strcmp(op, "and") || !strcmp(op, "or")){
      if(a->type == BOOL && b->type == BOOL){
	fprintf(fichier, "%s = %s i1 %s, %s\n", retour->nom, op, a->nom, b->nom);
      }
      else if(a->type != BOOL && b->type == BOOL){
	fprintf(fichier, "%s = %s i1 true, %s\n", retour->nom, op, b->nom);
      }
      else if(a->type == BOOL && b->type != BOOL){
	fprintf(fichier, "%s = %s i1 true, %s\n", retour->nom, op, a->nom);
      }
      else{
	fprintf(fichier, "%s = %s i1 true, true\n", retour->nom, op);
      }
      return BOOL;
    }
    else if(!strcmp("aff", op)){
      switch(b->type){
      case(UNDEF):
	printf("Affection de la variable %s, dont le type est non défini.\n", b->nom);
	exit(1);
	break;
      case(INTEG):
	fprintf(fichier, "%s = alloca int\n", a->nom);
	fprintf(fichier, "store int %s, int* %s\n", a->nom, b->nom);
	return INTEG;
	break;
      case(FLOA):
	fprintf(fichier, "%s = alloca float\n", a->nom);
	fprintf(fichier, "store float %s, float* %s\n", a->nom, b->nom);
	return FLOA;
	break;
      case(BOOL):
	fprintf(fichier, "%s = alloca i1\n", a->nom);
	fprintf(fichier, "store i1 %s, i1* %s\n", a->nom, b->nom);
	return BOOL;
	break;
      default:
	printf("Le type de la variable %s n'est pas bon pour l'affectation. Le type est : %d\n", b->nom, b->type);
	break;
      }
    }
    else if(!strcmp("if", op)) {
      variable* var = empty_var();
      if(a->type == BOOL){
	var = a;
      }
      else{//Toute variable non booléenne est considéré comme étant true
	var->type = BOOL;
	var->nom = "true";
      }
      fprintf(fichier, "br i1 %s, label ifTrue%d, label ifFalse%d\nifTrue%d:\n", var->nom, numLabel, numLabel, numLabel);
      fprintf(fichier, "booleen%d = add i1 %s, 0\n", numLabel, var->nom);
    }
    else if(!strcmp("endif", op)){
      fprintf(fichier, "ifFalse%d:\n\n", numLabel); numLabel++;
    }
    else if(!strcmp("else", op)){
      fprintf(fichier, "ifFalse%d:\n\n", numLabel);
      fprintf(fichier, "br i1 booleen%d", numLabel); numLabel++;
      fprintf(fichier,", label ifTrue%d, label ifFalse%d\nifTrue%d:\n", numLabel, numLabel, numLabel);
    }
    else if(!strcmp("for", op)){
      if(a->type != INTEG || b->type != INTEG){
	printf("Erreur dans un for, une des 2 bornes n'est pas un entier\n");
	exit(1);
      }
      fprintf(fichier, "%%%d = icomp eq i32 %s, %s\n", derReg, a->nom, b->nom);
      fprintf(fichier, "br i1 %%%d, label ifTrue%d, label ifFalse%d\n", derReg, numLabel, numLabel); derReg++;
      fprintf(fichier, "ifTrue%d:\n", numLabel);
    }
    else if(!strcmp("endfor", op)){
      fprintf(fichier, "%%%d = add i32 %s, 1\n", derReg, a->nom); derReg++;
      fprintf(fichier, "%%%d = icomp eq i32 %d, %s\n", derReg, derReg-1, b->nom);
      fprintf(fichier, "br i1 %%%d, label ifTrue%d, label ifFalse%d\n", derReg, numLabel, numLabel);
      fprintf(fichier, "ifFalse%d:\n", numLabel);
    }
    else if(!strcmp("endwhile", op)){
      fprintf(fichier, "br i1 %s, label beginWhile%d, label endWhile%d\n", a->nom, numLabel, numLabel);
      fprintf(fichier, "beginWhile%d:\n", numLabel);
    }
    else if(!strcmp("endwhile", op)){
      fprintf(fichier, "br i1 %s, label beginWhile%d label endWhile%d\n", a->nom, numLabel, numLabel);
      fprintf(fichier, "endWhile%d:\n\n", numLabel); numLabel++;
    }
    else if(!strcmp("ret", op)){
      switch(a->type){
      case(INTEG):
      fprintf(fichier, "ret i32 %s\n", a->nom);
	return INTEG;
	break;
      case(FLOA):
	fprintf(fichier, "ret float %s\n", a->nom);
	break;
      case(BOOL):
	fprintf(fichier, "ret i1 %s\n", a->nom);
      default:
	fprintf(fichier, "ret void\n");
      }
    }
    else if(!strcmp("load", op)){
      fprintf(fichier, "%%%d = load i32 %s\n", derReg, a->nom);
      free(a->nom);
      a->nom = malloc(MAX_LEN_NBR_REG*sizeof(char));
      sprintf(a->nom, "%%%d", derReg); derReg++;
    }
  }

  variable* empty_var(){
    variable* newVar;
    newVar = malloc(sizeof(variable));
    newVar->nom = malloc(MAX_LEN_NBR_REG*sizeof(char));
    newVar->probType = NULL;
    newVar->type = UNDEF;
    return newVar;
  }

  instruction* empty_instr(){
    instruction* newInstr;
    newInstr = malloc(sizeof(instruction));
    newInstr->fonction = NULL;
    newInstr->parametres = NULL;
    newInstr->retour = empty_var();
    newInstr->next = NULL;
    return newInstr;
  }

  node* creerNode(node* nSuiv, char* nomVar, unType type){
    node* newNode = malloc(sizeof(node));
    int i;

    if(type == FONCTION){//il s'agit d'une fonction
      newNode->f = malloc(sizeof(function));
      newNode->f->retour = empty_var();
      newNode->f->retour->type = type;
      newNode->f->parametres = NULL;
      newNode->f->nom = malloc((strlen(nomVar)+1)*sizeof(char));
      strcpy(newNode->f->nom, nomVar);

    }
    else if(type == PARAMETRE){//il s'agit d'un parametre de fonction
      newNode->v = empty_var();
      newNode->v->type = type;
      newNode->v->probType = malloc((nbr_type+1)*sizeof(int));
      for(i = 0; i<nbr_type; i++){
	newNode->v->probType[i] = 1; 
      }
      newNode->v->nom = malloc((strlen(nomVar)+1)*sizeof(char));
      strcpy(newNode->v->nom, nomVar);
    }
    else{//Il s'agit d'une variable
      newNode->v = empty_var();
      newNode->v->type = type;
      newNode->v->nom = malloc((strlen(nomVar)+1)*sizeof(char));
      strcpy(newNode->v->nom, nomVar);
    }

    newNode->nSuiv = nSuiv;
    //    free(nomVar);

    return newNode;
  }

  /*
   *Cette fonction permet de chercher le node
   *dans la liste donnée, ayant le nom contenu dans
   *"nom".
   */
  node* chercheNode(char* nom, node* liste){
    node* currentNode = liste;
    while(currentNode != NULL){
      if(strcmp(currentNode->v->nom, nom) == 0){
	return currentNode;
      }
      currentNode = currentNode->nSuiv;
    }
    return NULL;
  }

  void deleteInstr(instruction* i){
    if(i != NULL){
      instruction* suivant = i->next;
      free(i);
      deleteInstr(i->next);
    }
  }

  void generiqueOp(char* op, variable* a, variable* b, variable* retour){
  instruction* instr = empty_instr();
    if(!strcmp(op, "add") || !strcmp(op, "sub") || !strcmp(op, "mul") || !strcmp(op, "div") || !strcmp(op, "eq") || !strcmp(op, "ne") || !strcmp(op, "ge") || !strcmp(op, "gt") || !strcmp(op, "lt") || !strcmp(op, "le") || !strcmp(op, "and") || !strcmp(op, "or")) {
      instr->fonction = malloc((strlen(op)+1)*sizeof(char*));
      strcpy(instr->fonction, op);
      node *param2 = creerNode(NULL, b->nom, b->type);
      instr->parametres = creerNode(param2, a->nom, a->type);
      instr->retour = retour;
      tailInstr->next = instr;
      tailInstr = instr;
      if(a->type == UNDEF && b->type != UNDEF){
	a->type = b->type;
      }
      else if(a->type != UNDEF && b->type == UNDEF){
	b->type = a->type;
      }
      if(a->type == b->type){
	instr->retour->type = a->type;
      }
    }
    else if(!strcmp("if", op) || !strcmp("endif", op) || !strcmp("else", op) || !strcmp("while", op) || !strcmp("endwhile", op)){
      instr->fonction = malloc((strlen(op)+1)*sizeof(char*));
      strcpy(instr->fonction, op);
      node *param2 = creerNode(NULL, b->nom, b->type);
      instr->parametres = creerNode(param2, a->nom, a->type);
      instr->retour = retour;
      tailInstr->next = instr;
      tailInstr = instr;
    }
    else if(!strcmp("ret", op)){
      instr->fonction = malloc((strlen(op)+1)*sizeof(char*));
      strcpy(instr->fonction, op);
      node *param2 = creerNode(NULL, b->nom, b->type);
      instr->parametres = creerNode(param2, a->nom, a->type);
      instr->retour = retour;
      tailInstr->next = instr;
      tailInstr = instr;
      tailFunc->f->retour = a;
    }
    else if(!strcmp(op, "aff") || !strcmp("for", op) || !strcmp("endfor", op)){
      instr->fonction = malloc((1+strlen(op))*sizeof(char));
      strcpy(instr->fonction, op);
      node *param2 = creerNode(NULL, b->nom, b->type);
      param2->v = b;
      instr->parametres = creerNode(param2, a->nom, a->type);
      instr->parametres->v = a;
      instr->retour = retour;
      tailInstr->next = instr;
      tailInstr = instr;
      if(a->type == UNDEF && b->type != UNDEF){
	a->type = b->type;
      }
    }
  }

  void ecrireFonction(){

  switch(tailFunc->f->retour->type){
  case(INTEG):
    fprintf(fichier, "define i32 %s(", tailFunc->f->nom);
    break;
  case(FLOA):
    fprintf(fichier, "define float %s(", tailFunc->f->nom);
    break;
  case(BOOL):
    fprintf(fichier, "define i1 %s(", tailFunc->f->nom);
    break;
  case(FONCTION):
    fprintf(fichier, "define void %s(", tailFunc->f->nom);
    tailFunc->f->retour->type = VOID;
    break;
  case(PARAMETRE):
    fprintf(fichier, "Cette fonction est du type passé en parametre. Je ne le connais pas encore.\n");
    break;
  case(VOID):
    fprintf(fichier, "define void %s(", tailFunc->f->nom);
    break;
  default:
    printf("Je n'ai pas réussi à déterminer le type de la fonction : %s\n Voila le switch : %d\n", tailFunc->f->nom, tailFunc->f->retour->type);
    break;
  }

  node* currentNode = tailFunc->f->parametres;
  //ecriture des parametres dans la définition de la fonction
  if(currentNode != NULL){
    fprintf(fichier, "%s", currentNode->v->nom);
    currentNode = currentNode->nSuiv;
  }
  while(currentNode != NULL){
    fprintf(fichier,", %s", currentNode->v->nom);
    currentNode = currentNode->nSuiv;
  }
  fprintf(fichier, "){\n");//fin de la déclaration

  //exploration des instructions
  instruction* currentInstr = headInstr->next;
  while(currentInstr != NULL){
    int i;
    node* an;
    node* bn;
    variable* a;
    variable* b;
    if((chercheNode(currentInstr->parametres->v->nom, headVar)) != NULL){
      an = chercheNode(currentInstr->parametres->v->nom, headVar);
      a = an->v;
    }
    else
      a = currentInstr->parametres->v;
    if((chercheNode(currentInstr->parametres->nSuiv->v->nom, headVar)) != NULL){
      bn = chercheNode(currentInstr->parametres->nSuiv->v->nom, headVar);
      b = bn->v;
      }
    else
      b = currentInstr->parametres->nSuiv->v;

    variable* retour = currentInstr->retour;

    retour->type = printCmd(currentInstr->fonction, a, b, retour);
    //    printf("Je printe %s avec %s = %d. Le retour est %s = %d\n", currentInstr->fonction, b->nom, b, retour->nom, retour);
    currentInstr = currentInstr->next;
  }
  fprintf(fichier, "}\n\n");
}

  /*
   * Renvoie vrai si il existe un paramètre dont le type n'a pas été définit en une passe.
   * Doit être executé sur une liste de variable.
   */
  int existParamUndef(node* liste){
    node* currentNode = liste->nSuiv;
    while(currentNode != NULL){
      if(currentNode->v->type == PARAMETRE)
	return 1;
      currentNode = currentNode->nSuiv;
    }
    return 0;
  }

  /*
   *Cette fonction printe une fonction
   *pour toutes les combinaisons de types 
   *des paramètres dont on a pas réussi à
   *déterminer le type.
   */
  void affectType(){
    if(tailFunc->f->parametres == NULL){
      printf("Erreur : il existe des parametres indéfini et pourtant la liste des parametres de la fonction %s est vide.", tailFunc->f->nom);
    }
    node* firstNode = tailFunc->f->parametres;
    affectTypeRecurs(firstNode);
  }
  /*
   *La fonction précédente étant récursive,
   *elle utilise cette fonction.
   */
  void affectTypeRecurs(node* parametre){
    if(parametre == NULL){//fin de la recursivité
      ecrireFonction();
    }
    else{
      int i;
      node* var = chercheNode(parametre->v->nom, headVar);
      for(i = 0; i < nbr_type; ++i){
	if(parametre->v->probType[i] == 1){
	  switch(i){
	  case (0):
	    printf("Erreur : Il n'a pas été possible de déterminer le type de %s\n", parametre->v->nom);
	    break;
	  case(1):
	    var->v->type = INTEG;
	    break;
	  case(2):
	    var->v->type = STR;
	    break;
	  case(3):
	    var->v->type = FLOA;
	    break;
	  case(4):
	    var->v->type = BOOL;
	    break;
	  case(5):
	    var->v->type = VOID;
	    break;
	  default:
	    printf("Une erreur s'est produite lors de la détermination du type : %s\n", parametre->v->nom);
	  }
	  affectTypeRecurs(parametre->nSuiv);
	}
      }
    }
  }

  void determineType(char* op, variable* a){
    node* var = chercheNode(a->nom, tailFunc->f->parametres);
    int i;
    if(var!=NULL){
      for(i = 0; i < nbr_type; ++i){
	if(i == 0 || i == 2 || i == 4 || i == 5) 
	  var->v->probType[i] = 0;
      }
    }
  }
%}

%union{
  char* chaine;
  variable* id;
  function* f;
  node* n;
 }

%token AND OR CLASS IF THEN ELSE END WHILE DO DEF LEQ GEQ 
%token INT ID FLOAT STRING FOR TO RETURN IN NEQ

%type <id> lhs primary expr multiplicative_expr additive_expr comp_expr stmt th action
%type <n> opt_params params
%type <chaine> INT FLOAT STRING ID

%left '*'
%left '/'
%left '+' '-'
%left '<' '>' LEQ GEQ EQ
%left AND OR

%start program

%%

program		:  topstmts opt_terms 
;
topstmts        :
| topstmt
| topstmts terms topstmt
;
topstmt	        : CLASS ID term stmts opt_terms END 
                | CLASS ID '<' ID term stmts opt_terms END
                | stmt
;
stmts	        : /* none */
                | stmt
                | stmts terms stmt
                ;

stmt		: IF expr THEN {
		     if(headInstr == NULL){
		       printCmd("if", $2, empty_var(), empty_var());
		     }
		     else{
		       generiqueOp("if", $2, empty_var(), empty_var());
		     }
		     derReg++;
                } th
                | FOR ID IN expr TO expr {
		  if(headInstr == NULL){
		    printCmd("for", $4, $6, empty_var());
		  }
		  else{
		    generiqueOp("for", $4, $6, empty_var());
		  }
		  
		} terms stmts terms END{
		  if(headInstr == NULL){
		    printCmd("endfor", $4, $6, empty_var());
		  }
		  else{
		    generiqueOp("endfor", $4, $6, empty_var());
		  }
		 }
		| WHILE expr{
		  if(headInstr == NULL){
		    printCmd("while", $2, empty_var(), empty_var());
		  }
		  else{
		    generiqueOp("while", $2, empty_var(), empty_var());
		  }
		}
                 action{
		  if(headInstr == NULL){
		    printCmd("endwhile", $2, empty_var(), empty_var());
		  }
		  else{
		    generiqueOp("endwhile", $2, empty_var(), empty_var());
		  }
		 }
                | lhs '=' expr {
		  //inititalisation des nodes
		  node* newNode =  creerNode(NULL, $1->nom, $3->type);
		  tailVar->nSuiv = newNode;
		  tailVar = newNode;

		  if(headInstr == NULL){
		    printCmd("aff", $1, $3, empty_var());
		    fprintf(fichier, "\n");
		  }
		  else{
		    generiqueOp("aff", $1, $3, empty_var());
		  }
		  }
                | RETURN expr {
		  if(headInstr == NULL){
		    printCmd("ret", $2, empty_var(), empty_var());
		    fprintf(fichier, "\n");
		  }
		  else{
		    generiqueOp("ret", $2, empty_var(), empty_var());
		  }
		  $$ = empty_var();
 }

                | DEF ID opt_params {
		  headInstr = empty_instr();
		  tailInstr = headInstr;

		  char* nom = (char*) malloc((2+strlen($2))*sizeof(char));
		  nom[0]='@';
		  nom[1]='\0';
		  strcat(nom, $2);

		  node* newFunc = creerNode(NULL, nom, FONCTION);
		  tailFunc->nSuiv = newFunc;
		  tailFunc = newFunc;

		  newFunc->f->parametres = $3;

                }term stmts terms END {
                  node* currentNode = tailFunc->f->parametres;
		  
		  if(existParamUndef(headVar)){
		    affectType();
		  }
		  else{
		    ecrireFonction();
		  }

		  deleteInstr(headInstr);
		  headInstr = NULL;
		  tailInstr = NULL;
 }
;
action          : DO term stmts terms END 
                | term stmts terms END
;

th              :  stmts terms END {
                   if(headInstr == NULL)
		     printCmd("endif", empty_var(), empty_var(),empty_var());
		  else{
		    generiqueOp("endif", empty_var(), empty_var(), empty_var());
                  }
		 }
                |  stmts terms ELSE {
		   if(headInstr == NULL)
		     printCmd("else", empty_var(), empty_var(),empty_var());
		  else{
		    generiqueOp("else", empty_var(), empty_var(), empty_var());
                }
		 } stmts terms END {
                   if(headInstr == NULL)
		     printCmd("endif", empty_var(), empty_var(), empty_var());
		  else{
		    generiqueOp("endif", empty_var(), empty_var(), empty_var());
		  }
		 }
;

opt_params      :'(' ')'  {node* listParams = NULL;
                           $$ = listParams;} 
                | '(' params ')' {$$ = $2;}
;
params          : ID ',' params {
		    char* nom = (char*) malloc((1+strlen($1))*sizeof(char));
		    nom[0]='%';
		    nom[1]='\0';
		    strcat(nom, $1);
				 
		    $$ = creerNode($3, nom, PARAMETRE);}
                | ID  {
		  char* nom = (char*) malloc((1+strlen($1))*sizeof(char));
		  nom[0]='%';
		  nom[1]='\0';
		  strcat(nom, $1);
		  $$ = creerNode(NULL, nom, PARAMETRE);
}
;
 
 lhs             : ID {
                     $$=empty_var();
                     $$->nom = malloc((1+strlen($1))*sizeof(char));
		     $$->nom[0]='%';
		     $$->nom[1]='\0';
		     strcat($$->nom, $1);

		     node* var = chercheNode($$->nom, headVar);//si le noeud n'est pas dans la table, chercheNode renvoie NULL
		      if(var != NULL) {
			$$->type = var->v->type;
			if(headInstr == NULL)
			  printCmd("load", $$, empty_var(),empty_var());
			else{
			  generiqueOp("load", $$, empty_var(), empty_var());
			}
		      }
		      else if(tailFunc != NULL && (var = chercheNode($$->nom, tailFunc->f->parametres)) != NULL){
			  $$->type = var->v->type;
			}
		      else
			$$->type = UNDEF;
 }
                   | ID '.' primary {$$->nom = $1;}
                   | ID '(' exprs ')'{$$->nom = $1;}
;
exprs           : exprs ',' expr
                | expr
;

primary         : lhs {$$=$1;}
                | STRING  {
		  $$ = empty_var();
		  $$->nom = malloc((strlen($1)+1)*sizeof(char));
		  strcpy($$->nom, $1);
		  $$->type = STR;
}
                | FLOAT {
		  $$ = empty_var();
		  $$->nom = malloc((strlen($1)+1)*sizeof(char));
		  strcpy($$->nom, $1);
		  $$->type = FLOA;
}
                | INT {
		  $$ = empty_var();
		  $$->nom = malloc((strlen($1)+1)*sizeof(char));
		  strcpy($$->nom, $1);
		  $$->type = INTEG;
}
                | '(' expr ')' {$$ = $2;}
;
expr            : expr AND comp_expr {
                     $$ = empty_var();
		     sprintf($$->nom, "%%%d", derReg);
		     if(headInstr == NULL){
		       $$->type = printCmd("and", $1, $3, $$);
		     }
		     else{
		       generiqueOp("and", $1, $3, $$);
		       determineType("and", $1);
		       determineType("and", $3);
		     }
		     derReg++;
                 }
                | expr OR comp_expr {
                     $$ = empty_var();
		     sprintf($$->nom, "%%%d", derReg);
		     if(headInstr == NULL){
		       $$->type = printCmd("or", $1, $3, $$);
		     }
		     else{
		       generiqueOp("or", $1, $3, $$);
		       determineType("or", $1);
		       determineType("or", $3);
		     }
		     derReg++;
                 }
                | comp_expr
;

 comp_expr       : additive_expr '<' additive_expr {//<
                     $$ = empty_var();
		     sprintf($$->nom, "%%%d", derReg);
		     if(headInstr == NULL){
		       $$->type = printCmd("lt", $1, $3, $$);
		     }
		     else{
		       generiqueOp("lt", $1, $3, $$);
		       determineType("lt", $1);
		       determineType("lt", $3);
		     }
		     derReg++;
 }
                   | additive_expr '>' additive_expr {//>
		       $$ = empty_var();
		       sprintf($$->nom, "%%%d", derReg);
		       if(headInstr == NULL){
			 $$->type = printCmd("gt", $1, $3, $$);
		       }
		       else{
			 generiqueOp("gt", $1, $3, $$);
			 determineType("gt", $1);
			 determineType("gt", $3);
		  }
		  derReg++;
  }
		     | additive_expr LEQ additive_expr{//<=
		       $$ = empty_var();
		       sprintf($$->nom, "%%%d", derReg);
		       if(headInstr == NULL){
			 $$->type = printCmd("le", $1, $3, $$);
		       }
		       else{
			 generiqueOp("le", $1, $3, $$);
			 determineType("le", $1);
			 determineType("le", $3);
		  }
		  derReg++;
 }

                | additive_expr GEQ additive_expr{//>=
		  $$ = empty_var();
		  sprintf($$->nom, "%%%d", derReg);
		  if(headInstr == NULL){
		    $$->type = printCmd("ge", $1, $3, $$);
		  }
		  else{
		    generiqueOp("ge", $1, $3, $$);
		    determineType("ge", $1);
		    determineType("ge", $3);
		  }
		  derReg++;
 }
                | additive_expr EQ additive_expr{//==
		  $$ = empty_var();
		  sprintf($$->nom, "%%%d", derReg);
		  if(headInstr == NULL){
		    $$->type = printCmd("eq", $1, $3, $$);
		  }
		  else{
		    generiqueOp("eq", $1, $3, $$);
		    determineType("eq", $1);
		    determineType("eq", $3);
		  }
		  derReg++;
 }
                | additive_expr NEQ additive_expr{//!=
		   $$ = empty_var();
		   sprintf($$->nom, "%%%d", derReg);
		   if(headInstr == NULL){
		     $$->type = printCmd("ne", $1, $3, $$);
		   }
		   else{
		     generiqueOp("ne", $1, $3, $$);
		     determineType("ne", $1);
		     determineType("ne", $3);
		   }
		   derReg++;
 }
                | additive_expr {$$ = $1;}
;

 additive_expr   : multiplicative_expr {$$ = $1;}
                 | additive_expr '+' multiplicative_expr {
		   $$ = empty_var();
		   sprintf($$->nom, "%%%d", derReg);
		   if(headInstr == NULL){
		     $$->type = printCmd("add", $1, $3, $$);
		   }
		   else{
		     generiqueOp("add", $1, $3, $$);
		     determineType("add", $1);
		     determineType("add", $3);
		   }
		   derReg++;
		   }
                 | additive_expr '-' multiplicative_expr {
		   $$ = empty_var();
		   sprintf($$->nom, "%%%d", derReg);
		   if(headInstr == NULL){
		     $$->type = printCmd("sub", $1, $3, $$);
		   }
		   else{
		     generiqueOp("sub", $1, $3, $$);
		     determineType("sub", $1);
		     determineType("sub", $3);
		   }
		   derReg++;
		   }
;

multiplicative_expr : multiplicative_expr '*' primary {
                      $$ = empty_var();
		      sprintf($$->nom, "%%%d", derReg);
                      if(headInstr == NULL){
			$$->type = printCmd("mul", $1, $3, $$);
		      }
		      else{
			generiqueOp("mul", $1, $3, $$);
			determineType("mul", $1);
			determineType("mul", $3);
		      }
		      derReg++;
 }
                    | multiplicative_expr '/' primary {
                      $$ = empty_var();
		      sprintf($$->nom, "%%%d", derReg);
		      if(headInstr == NULL){
			$$->type = printCmd("div", $1, $3, $$);
		      }
		      else{
			generiqueOp("div", $1, $3, $$);
			determineType("div", $1);
			determineType("div", $3);
		      }
		      derReg++;
		      }
                     | primary {
		       $$ = $1;}
;

opt_terms	: /* none */
		| terms
		;

terms		: terms ';'
                | terms '\n'
		| ';'
                | '\n'
		;
term            : ';'
                | '\n'
;


%%

int main() {
  node* buffer;

  fichier = fopen("result.ll", "w+");

  headVar = creerNode(NULL, "", -1);
  tailVar = headVar;

  headFunc = creerNode(NULL, "", -1);
  tailFunc = headFunc;

  yyparse(); 

  node* currentNode = headVar;
  while(currentNode->nSuiv != NULL){
    free(currentNode->v->nom);
    buffer = currentNode;
    currentNode = currentNode->nSuiv;
    free(buffer);
  }

  fclose(fichier);
  return 0;
}
